package com.flyme.common.reader;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

import java.util.List;

/**
 *
 */
@Slf4j
public abstract class AbstractPagingReader<T> {

    // reader name
    private String name;

    private volatile boolean initialized = false;

    private int pageSize = 100;

    private volatile int current = 0;

    private volatile int page = 0;

    protected volatile List<T> results;

    private Object lock = new Object();

    public AbstractPagingReader() {
        setName(ClassUtils.getShortName(AbstractPagingReader.class));
    }

    /**
     * The current page number.
     *
     * @return the current page
     */
    public int getPage() {
        return page;
    }

    /**
     * The page size configured for this reader.
     *
     * @return the page size
     */
    public int getPageSize() {
        return pageSize;
    }

    /**
     * The number of rows to retrieve at a time.
     *
     * @param pageSize the number of rows to fetch per page
     */
    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public T read() throws Exception {

        synchronized (lock) {

            if (results == null || current >= pageSize) {
                doReadPage();
                page++;
                if (current >= pageSize) {
                    current = 0;
                }
            }

            int next = current++;
            if (next < results.size()) {
                return results.get(next);
            } else {
                return null;
            }

        }

    }

    /**
     * 读取分页的结果集
     *
     * @return
     * @throws Exception
     */
    public List<T> readAll() throws Exception {
        synchronized (lock) {
            if (results == null || current >= pageSize) {
                doReadPage();
                page++;
            }
            return results;
        }
    }


    abstract protected void doReadPage();

    public void open() throws Exception {
        Assert.state(!initialized, "Cannot open an already opened Reader, call close first");
        initialized = true;

    }

    public void close() throws Exception {
        synchronized (lock) {
            initialized = false;
            current = 0;
            page = 0;
            results = null;
        }

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
